/**
 * 使用自定义协议的tcp多进程模型-服务端
*/

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <time.h>

#include <arpa/inet.h>

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>

#include "msg.h"

#define PORT 9999
#define LISTEN_MAXNUM 10

static int tcp_server_init()
{
    int socketfd = socket(AF_INET, SOCK_STREAM, 0);
    if (socketfd < 0)
    {
        perror("socket error: ");
        return -1;
    }

    struct sockaddr_in serverAddr;
    memset(&serverAddr, 0, sizeof(struct sockaddr_in));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(PORT);
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);

    if (bind(socketfd, (struct sockaddr *)&serverAddr, sizeof(struct sockaddr)) < 0)
    {
        perror("bind error: ");
        close(socketfd);
        return -1;
    }

    if (listen(socketfd, LISTEN_MAXNUM) < 0)
    {
        perror("listen error: ");
        close(socketfd);
        return -1;
    }

    return socketfd;
}

static void out_client_info(struct sockaddr_in clientAddr)
{
    char *ip = inet_ntoa(clientAddr.sin_addr);
    unsigned short port = ntohs(clientAddr.sin_port);
    printf("Connection from %s:%d\n", ip, port);
}

static void signal_handler(int signum)
{
    if (signum == SIGCHLD)
    {
        printf("client exit!\n");
        wait(0);
    }
}

int main(void)
{
    int sockfd = tcp_server_init();
    if (sockfd == -1)
    {
        exit(EXIT_FAILURE);
    }

    signal(SIGCHLD, signal_handler);

    struct sockaddr_in clientAddr;
    socklen_t addrlen = sizeof(clientAddr);
    while (1)
    {
        int newfd = accept(sockfd, (struct sockaddr *)&clientAddr, &addrlen);
        if (newfd < 0)
        {
            perror("accept error: ");
            close(sockfd);
            exit(EXIT_FAILURE);
        }

        pid_t pid = fork();
        if (0 > pid)
        {
            perror("fork error: ");
            exit(EXIT_FAILURE);
        }
        else if (0 == pid)
        {
            out_client_info(clientAddr);
            while (1)
            {
                char buff[1024] = {0};
                int len = read_msg(newfd, buff, 1024);
                if (len <= 0)
                {
                    break;
                }
                printf("client msg %s\n", buff);

                write_msg(newfd, buff, strlen(buff));
            }
            printf("exit child progress!\n");

            close(newfd);
            exit(EXIT_SUCCESS);
        }
        else
        {
            close(newfd);
        }
    }

    return 0;
}